using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;
using Sedna.Core.Controller.Configurations;
using Sedna.Core.Controls.Support;
using Sedna.Core.Controller;
using Sedna.Core.Controls.Support.Javascript;
using Sedna.Core.DataBinding;
using Sedna.Core.Tiles.Contents;
using DataBinder=Sedna.Core.DataBinding.DataBinder;

namespace Sedna.Core.Controls
{
    public class DropDownList : System.Web.UI.WebControls.DropDownList, IContent, IConfigurationAware, IClientScriptingControl, IControlDataLoadAware, IListControl, IControlBindingAware
	{
		private bool clientScriptingEnabled=false;
		private string clientVariable=null;
//		private int fieldId;
		
		private String contentPlaceHolderId;

		protected IDataBinder binder;
        private ISingleSelectListController controller;
		private IConfiguration configuration;
		private string configurationId;
	    private bool addEmptyItem;
        private string emptyItemText;
        private string emptyItemTextKey;
        private string emptyItemValue;

        private string javascriptClass;

        private string toolTipKey;
        public virtual string ToolTipKey
        {
            get { return toolTipKey; }
            set { toolTipKey = value; }
        }

        public string LocalizedToolTip
        {
            get
            {
                if (Configuration.DataTranslator != null && Configuration.DataTranslator.GetType() != typeof(TrivialDataTranslator))
                {
                    return ToolTip;
                }
                return Configuration.GetLocalizedPostfixLabel(ToolTipKey, ToolTip);
            }
        }


        #region Properties

	    public IDropDownListConfiguration Configuration
	    {
            get { return (IDropDownListConfiguration) configuration; }
            set { configuration = value; }
	    }
	    
        public String ContentPlaceHolderId
		{
			get { return contentPlaceHolderId;}
			set { contentPlaceHolderId = value;}
		}


        IConfiguration IConfigurationAware.Configuration
		{
			get { return configuration; }
			set { this.configuration = value; }
		}

		[Bindable(true), Category("Sedna"), DefaultValue("configuration.default.DropDownList")]
		public string ConfigurationId
		{
			get { return configurationId; }
			set { this.configurationId = value; }
		}
	
        public bool ClientScriptingEnabled
        {
            get { return clientScriptingEnabled /*|| clientVariable != null*/; }
            set { clientScriptingEnabled = value; }
        }

        public string ClientVariable
        {
            get { return ControlUtil.GetClientVariable(this, clientVariable); }
            set { clientVariable = value; }
        }

        public ISingleSelectListController Controller
	    {
	        get { return controller; }
	        set
	        {
                if (value == null && controller != null)
                {
                    controller.OnControlChanged -= new ControlHandler(Controller_OnControlChanged);
                    
                    if (controller.Control == this)
                        controller.Control = null;
                }
	            
	            controller = value;

                if (controller != null)
                {
                    controller.Control = this;
                    controller.OnControlChanged += new ControlHandler(Controller_OnControlChanged);
                }
	        }
	    }

        public IList<ListItem> SelectedItems
        {
            get
            {
                IList<ListItem> list = new List<ListItem>();

                if (SelectedItem != null)
                    list.Add(SelectedItem);

                return list;
            }
        }

        public IList<String> SelectedValues
        {
            get
            {
                IList<String> list = new List<String>();

                if (SelectedValue != null)
                    list.Add(SelectedValue);

                return list;
            }
        }

	    public string SelectedText
		{
			get { return (SelectedItem != null ? SelectedItem.Text : String.Empty); }
        }

	    public bool AddEmptyItem
	    {
	        get { return addEmptyItem; }
	        set { addEmptyItem = value; }
	    }

	    public string EmptyItemText
	    {
	        get { return emptyItemText; }
	        set { emptyItemText = value; }
	    }

	    public string EmptyItemTextKey
	    {
	        get { return emptyItemTextKey; }
	        set { emptyItemTextKey = value; }
	    }

	    public string EmptyItemValue
	    {
	        get { return emptyItemValue; }
	        set { emptyItemValue = value; }
	    }

	    #endregion

        #region Javascript support

        public string JavascriptClass
        {
            get { return javascriptClass; }
            set { javascriptClass = value; }
        }

        public string NodeName
        {
            get { return ClientID; }
        }


        private void RenderScriptAttributes(HtmlTextWriter writer)
        {
            foreach (DictionaryEntry entry in BuildScriptParameters())
            {
                writer.AddAttribute("sedna:" + (string)entry.Key, (string)entry.Value);
            }
        }

        private void DeclareScriptVariable()
        {
            ControlUtil.EnsureIdAttribute(this);
            JavascriptController.Current.DeclareClass(JavascriptClass);
            if (ClientVariable != null)
            {
                JavascriptController.Current.DeclareObjectByNode(ClientVariable, JavascriptClass, NodeName);
            }
        }

        protected virtual IDictionary BuildScriptParameters()
        {
            IDictionary parameters = new ListDictionary();
            parameters.Add("jsClass", JavascriptClass);
            parameters.Add("id", ClientID);
            parameters.Add("autoPostBack", AutoPostBack.ToString().ToLower());
            parameters.Add("submitState",  this.SelectedItem != null ? this.SelectedItem.Text : "");
            return parameters;
        }

        #endregion

        # region Events

        public event BindingHandler BeforeBinding;
        public event BindingHandler AfterBinding;
        public event BindingHandler BeforeUnbinding;
        public event BindingHandler AfterUnbinding;

        # endregion

		public DropDownList(IConfiguration configuration)
		{
            javascriptClass = "DropDown";
			this.CssClass = "inputsmall";
			this.Width = Unit.Pixel(120);
			this.configuration = configuration;
			this.configurationId= configuration.ObjectName;

            Build();
		}

		protected override void OnInit(EventArgs e)
		{
			if (configuration == null) 
			{
				configuration = (IConfiguration)SpringContextFactory.GetContext().GetObject(configurationId);
                Build();
			}
			ControlUtil.SetupClientAttributes(this, configuration);
            SelectedIndexChanged+=new EventHandler(OnSelectedIndexChanged);
			binder=new DataBinder(this, configuration, ExecutionContext.GetCurrent(ClientID));			
			base.OnInit (e);
		}

        public void UnselectAll()
        {
            foreach (ListItem item in SelectedItems)
            {
                item.Selected = false;
            }
        }

		protected void OnSelectedIndexChanged(object sender, EventArgs e)
		{
			IExecutionContext executionContext = ExecutionContext.GetCurrent(ClientID);
//			if (AutoPostBack)
//			{
//				executionContext["infrastructure.PostBackSourceControl"]=ExecutionContextPrefix;
//			}
			ControlUtil.ExecuteAction(executionContext, Context, Configuration, this.ClientID);
            ControlUtil.ExecuteAction(executionContext, Context, Configuration, this.ClientID, "onSelectedIndexChanged");
			RaiseBubbleEvent(this, new ModelUpdateEventArgs(executionContext));
		}
	    	    
		protected void Build()
		{
		    if (configuration.Id!=null)
		    {
                this.ID = Configuration.Id;
		    }
			if (!configuration.Width.IsEmpty)
			{
				Width= configuration.Width;
			}

			ClientScriptingEnabled=Configuration.ClientScriptingEnabled;
			ClientVariable=Configuration.ClientVariable;

            this.Enabled = Configuration.Enabled && this.configuration.IsEnabledForPrincipal();
            this.Visible = Configuration.Visible && this.configuration.IsVisibleForPrincipal();

			AutoPostBack=Configuration.AutoPostBack;

            DataTextField = Configuration.DataTextField;
            DataValueField = Configuration.DataValueField;
            AddEmptyItem = Configuration.AddEmptyItem;
            EmptyItemText = Configuration.EmptyItemText;
            EmptyItemTextKey = Configuration.EmptyItemTextKey;
            EmptyItemValue = Configuration.EmptyItemValue;

            Controller = Configuration.Controller != null ? (ISingleSelectListController)Configuration.Controller.Clone() : null;            
		}

        void Controller_OnControlChanged(Control control)
        {
            if (control != this)
                Controller = null;
        }

	    protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			IDictionary executionContext = ExecutionContext.GetCurrent(ClientID);			
			Unbind();
			ControlUtil.ExecuteOnLoad(executionContext, Context, Configuration, this.ClientID);
		    
		    if (Configuration.VisibleBindPath != null)
                this.Visible = true; // To reach the OnPreRender method and analyze visibility in the Bind method
		}

		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender (e);
			IDictionary executionContext = ExecutionContext.GetCurrent(ClientID);
			ControlUtil.ExecuteOnPreRender(executionContext,Context, Configuration, this.ClientID);
   		    Bind();
            ToolTip = LocalizedToolTip;
			if (ClientScriptingEnabled)
			{
//				EnableClientScripting();
			    DeclareScriptVariable();
			}

		}


	    protected override void AddAttributesToRender(HtmlTextWriter writer)
	    {
	        base.AddAttributesToRender(writer);
	        RenderScriptAttributes(writer);
	    }

//		private void EnableClientScripting()
//		{
//			ControlUtil.EnsureIdAttribute(this);
//
//            JavascriptController controller = JavascriptController.Current;
//
//			controller.DeclareClass("DropDown");
//            controller.DeclareObjectWithQuotedParams(ClientVariable, "DropDown", ClientID, AutoPostBack, this.SelectedItem != null ? this.SelectedItem.Text : "");			
//		}

		public void OnDataLoad()
		{
			IDictionary executionContext = ExecutionContext.GetCurrent(ClientID);
			ControlUtil.ExecuteOnDataLoad(executionContext, Context, Configuration, this.ClientID);
		}

		private void BindDataSource()
        {
            # region Setting data fields
		    
            object dataTextField = Configuration.DataTextField;

            if (String.IsNullOrEmpty(Configuration.DataTextField) && !binder.GetPropertyValue("DataTextField", out dataTextField))
            {
                dataTextField = "Text";
            }
		    
		    object dataValueField = Configuration.DataValueField;

            if (String.IsNullOrEmpty(Configuration.DataValueField) && !binder.GetPropertyValue("DataValueField", out dataValueField))
            {
                dataValueField = "Value";
            }

            DataTextField = dataTextField.ToString();
            DataValueField = dataValueField.ToString();

            # endregion

            /* Neither of sort order, sort expression, virtual item count and etc. must save by grid instance,
             * all of these were replaced to the IFilterState and IGridController */
            if (Controller != null)
            {
                Controller.LoadOrRefresh();
            }
            else
            {
                object dataSource = null;
                
                if (!binder.GetPropertyValue("DataSource", out dataSource))
                {
                    return; //No source sould be binded;
                }

                DataSource = TranslateData(dataSource, (string)dataValueField, (string)dataTextField);

                DataBind();
            }            			
		}

		private void Bind()
		{
            try
            {
                if (BeforeBinding != null)
                    BeforeBinding(this);

                Visible = configuration.Visible;
                // this.Enabled = this.configuration.Enabled;	It should not be here!	    

                BindDataSource();

                binder.Bind(new string[] { "Enabled", "Visible" });

                if (controller == null || String.IsNullOrEmpty(controller.SelectedItemPath))
                {
                    binder.Bind("SelectedIndex");
                    binder.Bind("SelectedValue", Configuration.SelectedValueDataTranslator);
                }

                Enabled = Enabled && configuration.IsEnabledForPrincipal();
                Visible = Visible && configuration.IsVisibleForPrincipal();

                ToolTip = Configuration.ToolTip;
                ToolTipKey = Configuration.ToolTipKey;
                binder.Bind("ToolTip");
                binder.Bind("ToolTipKey");

                
                if (AfterBinding != null)
                    AfterBinding(this);
            }
		    catch(Exception e)
            {
                throw new ControlBindingException(this, e);
            }
        }

		private void Unbind()
		{
            if (!Configuration.DoUnbind)
                return;
		    
            try
            {
                if (BeforeUnbinding != null)
                    BeforeUnbinding(this);

                binder.Unbind(new string[] { "SelectedIndex", "DataSource", "DataValueField", "DataTextField", "Enabled", "SelectedText", "Visible" });
                binder.Unbind("SelectedValue", configuration.DataParser);

                binder.Unbind("ToolTip");
                binder.Unbind("ToolTipKey");

                if (AfterUnbinding != null)
                    AfterUnbinding(this);
            }
		    catch(Exception e)
		    {
                throw new ControlBindingException(this, e);
		    }
		}

        private String GetEmptyElementText
        {
            get
            {
                String value = Configuration.GetLocalizedPostfixLabel(Configuration.EmptyItemTextKey, Configuration.EmptyItemText);

                if (value == null)
                    value = Configuration.EmptyItemText;

                return value;
            }
        }

		private IEnumerable TranslateData(object dataSource, string dataValueField, string dataTextField)
		{
			IEnumerable enumerable=ResolveDataSource(dataSource);
			
		    if (enumerable==null)
			{
				return null;
			}
		    
			DataTable dataTable=new DataTable();
			
		    dataTable.Columns.Add("Text", typeof(object));
			dataTable.Columns.Add("Value", typeof(object));
			
		    if (addEmptyItem)
			{
                DataRow dataRow = dataTable.NewRow();
                dataRow["Text"] = GetEmptyElementText;
                dataRow["Value"] = EmptyItemValue;
                dataTable.Rows.Add(dataRow);
			}
		    
		    bool isExtractTextAndValue=(dataValueField!=null)&&(dataValueField.Length>0)&&(dataTextField!=null)&&(dataTextField.Length>0);

            foreach (object item in enumerable)
            {
                DataRow dataRow = dataTable.NewRow();
                
                object text = isExtractTextAndValue ? System.Web.UI.DataBinder.GetPropertyValue(item, dataTextField) : item;
                
                dataRow["Text"] = Configuration.DataTranslator.Translate(this, text);
                dataRow["Value"] = isExtractTextAndValue ? System.Web.UI.DataBinder.GetPropertyValue(item, dataValueField) : item;
                
                dataTable.Rows.Add(dataRow);
            }
		    
			return dataTable.DefaultView;
		}

		private IEnumerable ResolveDataSource(object dataSource)
		{
			if (dataSource==null)
			{
				return null;
			}
			IListSource listSource=dataSource as IListSource;
			if (listSource!=null)
			{
				return listSource.GetList();
			}
			return dataSource as IEnumerable;
		}

	}
}
